package net.cloudcodex.server.service;

import java.util.ArrayList;
import java.util.List;

import net.cloudcodex.server.Context;
import net.cloudcodex.server.data.Data;
import net.cloudcodex.server.data.Data.Campaign;
import net.cloudcodex.server.data.Data.Notification;
import net.cloudcodex.server.data.Data.User;
import net.cloudcodex.server.data.home.CampaignPublicSummary;
import net.cloudcodex.server.data.home.CampaignSummary;
import net.cloudcodex.server.data.home.CharacterSummary;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query.FilterOperator;

/**
 * Service for Campaign
 * @author Thomas
 */
public class HomeService extends AbstractService {

	/**
	 * @param store Google AppEngine datastore.
	 */
	public HomeService(DatastoreService store) {
		super(store);
	}

	/**
	 * Searchs an user by its email.
	 */
	public Data.User getUserByEmail(Context context, String email) {
		return dao.getUserByEmail(context, email);
	}
	
	/**
	 * Searchs an user by its email.
	 */
	public Data.User getUserByGoogleId(Context context, String userId) {
		return dao.getUserByGoogleId(context, userId);
	}

	/**
	 * Utility method to create a user.
	 * TODO doesn't check anything ...
	 * 
	 * @param context execution context.
	 * @param email email of the user.
	 * @param nickname nickname of the user.
	 * @return the user created.
	 */
	public Data.User createUser(Context context, String email, String nickname) {
		
		final Data.User user = new Data.User();
		user.setEmail(email);
		user.setNickname(nickname);
		dao.save(context, user);

		return user;
	}
	
	/**
	 * @param context execution context.
	 * @return the characters summary data.
	 */
	public List<CharacterSummary> getCharacterSummaries(Context context) {

		final Data.User user = context.getUser();
		
		if(user == null) {
			return null;
		}
		
		// Search the characters.
		final List<Data.Character> characters = 
			dao.asListOfCharacters(context, dao.addCharacterFilterOnOwner(
				dao.queryCharacter(), FilterOperator.EQUAL, user.getKey()), null);
		
		if(characters == null || characters.isEmpty()) {
			return null;
		}
		
		final List<CharacterSummary> summaries = new ArrayList<CharacterSummary>();
		
		// Iterate over the characters to reach the other data
		for(Data.Character character : characters) {
			final Key key = character.getKey();
			
			// Search the campaign ...
			final Data.Campaign campaign = dao.readCampaign(context, key.getParent());
			if(campaign == null) {
				// FIXME Houston, we have a problem
				continue;
			}

			// ... and complete it.
			final CampaignPublicSummary campaignSummary = new CampaignPublicSummary();
			campaignSummary.setCampaign(campaign);
			campaignSummary.setNotifications(getNotifications(context, campaign.getKey()));
			campaignSummary.setMaster(dao.readUser(context, campaign.getMaster()));
			
			// Search the notifications. may be null.
			final List<Notification> notifications = getNotifications(context, key);
			
			final CharacterSummary summary = new CharacterSummary();
			summary.setCharacter(character);
			summary.setCampaign(campaignSummary);
			summary.setNotifications(notifications);
			
			summaries.add(summary);
		}
		
		return summaries.isEmpty() ? null : summaries;
	}
	
	/**
	 * @param context execution context.
	 * @return the characters summary data.
	 */
	public List<CampaignSummary> getCampaignSummaries(Context context) {

		final Data.User user = context.getUser();
		
		if(user == null) {
			return null;
		}

		final List<Campaign> campaigns =
			dao.asListOfCampaigns(context, dao.addCampaignFilterOnMaster(
				dao.queryCampaign(), FilterOperator.EQUAL, user.getKey()), null);

		if(campaigns == null || campaigns.isEmpty()) {
			return null;
		}
		
		final List<CampaignSummary> summaries = new ArrayList<CampaignSummary>();
		for(Campaign campaign : campaigns) {
			final CampaignSummary summary = new CampaignSummary();
			summary.setCampaign(campaign);
			summary.setMaster(user);
			summary.setNotifications(getNotifications(context, campaign.getKey()));
			summary.setCharacters(dao.getCampaignPlayableCharacters(context, campaign.getKey()));
			summaries.add(summary);
		}
		
		return summaries.isEmpty() ? null : summaries;
	}
	
	/**
	 * Registers a user not yet registered.
	 * @param nickname nickname to set to the user.
	 * @return the updated user or null when error occurs.
	 */
	public Data.User register(Context context, String nickname) {
		
		final User user = context.getUser();
		
		if(user.getNickname() != null) {
			return null;
		}

		// FIXME you can do a better check ...
		if(nickname == null || "".equals(nickname.trim())) {
			return null;
		}
		
		// Check the nickname is not already used.
		final List<Data.User> users =
			dao.filterUsersOnNickname(context, null, FilterOperator.EQUAL, nickname);
		
		if(users != null && !users.isEmpty()) {
			logger.severe("try to register with '" + nickname +"' but already used");
		}
		
		// Update the user.
		user.setNickname(nickname);
		dao.save(context, user);
		
		return user;
	}
	
}
